#light

/// Glues the different systems into the transaction system.
module CGraph.TransactionGlue
open System.Collections.Generic
open CGraph.Transactions
open CGraph.DirectedGraph
open CGraph.DirectedGraph.Impl
open CGraph.DocumentGraph
open CGraph.Generic
open CGraph.Generic.Impl;

/// Create a binding between a given transaction system and a directed graph.  This will enable the graph
/// to reset its state due to the abilities of the edge collection and vertex collection actions.
/// This system is OK if you intend to re-use the same directed graph for the life of the program.
/// I do not believe that the bindings used in here will allow the directed graph to go out of
/// scope, however.  Thus this system will most likely need fairly large
/// updates in the form of only talking to handles of various types so that this item does not
/// speak directly to any graph.
let GlueGraphActions ((transSystemOps:TransactionSystem), dgraph) =

    let createECA (trans:Transaction) = 
        let retval = new EdgeCollectionAction( dgraph, null, null )
        (trans :> IActionList).Add( retval )
        retval
        
    let createVCA (trans:Transaction) = 
        let retval = new VertexCollectionAction( dgraph, null, null )
        (trans :> IActionList).Add( retval )
        retval
        
    let currentTrans() = transSystemOps.Transaction
    let currentECA = ref None
    let currentVCA = ref None
    
    
    let GetOrCreateECA trans = 
        match !currentECA with
            | Some eca -> eca
            | None -> 
                let retval = createECA trans
                currentECA := Some (retval)
                retval
                    
                
    let GetOrCreateVCA trans = 
        match !currentVCA with
            | Some vca -> vca
            | None -> 
                let retval = createVCA trans
                currentVCA := Some ( retval )
                retval
    
    let AddVertex ((v:IVertex),(idx:int)) =
        match currentTrans() with
            | Some trans -> 
                let vca = GetOrCreateVCA trans
                vca.AddList.Add v
            | None -> ()
                
    let RemoveVertex ((v:IVertex),(idx:int)) =
        match currentTrans() with
            | Some trans -> 
                let vca = GetOrCreateVCA trans
                vca.RemoveList.Add v
            | None -> ()
                
    let AddEdge ((e:IEdge),(inC:int),(outC:int)) =
        match currentTrans() with
            | Some trans -> 
                let eca = GetOrCreateECA trans
                eca.AddList.Add e
            | None -> ()
                
    let RemoveEdge ((e:IEdge),(inC:int),(outC:int)) =
        match currentTrans() with
            | Some trans -> 
                let eca = GetOrCreateECA trans
                eca.RemoveList.Add e
            | None -> ()
                
    dgraph.VertexAddEvent.Add AddVertex
    dgraph.VertexRemoveEvent.Add RemoveVertex
    dgraph.EdgeAddEvent.Add AddEdge
    dgraph.EdgeRemoveEvent.Add RemoveEdge
    

/// Document graph is just a directed graph with two more events to listen to.
/// You shouldn't call GlueGraphActions with the graph used in this method,
/// that is implied, and is the first item done by this function
let GlueDocGraph((transSystem:TransactionSystem),(graph:DocumentGraph)) =
    GlueGraphActions( transSystem, (graph :> DirectedGraph))
    let currentTrans() = transSystem.Transaction
    let idSet (vert:IdVertex) (value:string) = vert.InternalSetId value
    let pathSet (vert:PathVertex) (value:string) = vert.InternalSetPath value
    
    graph.IdSetEvent.Add( 
        fun(oldV,newV,vert) ->
            match currentTrans() with
                | Some trans ->
                    (trans :> IActionList).Add(
                        PropertyAction<IdVertex,string>(
                            vert, oldV, newV, new PASetter<IdVertex,string>(idSet), "Id" ) );
                | None -> () );
                
    graph.PathSetEvent.Add( 
        fun(oldV,newV,vert) ->
            match currentTrans() with
                | Some trans ->
                    (trans :> IActionList).Add(
                        PropertyAction<PathVertex,string>(
                            vert, oldV, newV, new PASetter<PathVertex,string>(pathSet), "Path" ) );
                | None -> () );
                